package com.hdu;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
import java.util.concurrent.atomic.AtomicBoolean;

import static java.util.Optional.ofNullable;

public class EnhanceFutureTask<V> extends FutureTask<V> {

    private List<FutureListener<EnhanceFutureTask<V>>> successListeners;
    private List<FutureListener<EnhanceFutureTask<V>>> failureListeners;
    private List<FutureListener<EnhanceFutureTask<V>>> cancelListeners;
    private List<FutureListener<EnhanceFutureTask<V>>> finallyListeners;

    private AtomicBoolean CAN_SET_VALUE = new AtomicBoolean(true);
    private AtomicBoolean CAN_SET_EXCEPTION = new AtomicBoolean(true);


    private V res;
    private Throwable t;


    public EnhanceFutureTask(Callable<V> callable) {
        super(callable);
    }

    public static <V> EnhanceFutureTask<V> of(Callable<V> callable) {
        return new EnhanceFutureTask<>(callable);
    }

    @Override
    public boolean cancel(boolean mayInterruptIfRunning) {
        boolean result = super.cancel(mayInterruptIfRunning);
        if (result) {
            invokeListeners(cancelListeners);
        }
        return result;
    }

    @Override
    protected void set(V v) {
        super.set(v);
        // 防止重复set
        if (CAN_SET_VALUE.compareAndSet(true, false)) {
            res = v;
            invokeListeners(successListeners);
            invokeListeners(finallyListeners);
        }
    }

    @Override
    protected void setException(Throwable t) {
        super.setException(t);
        // 防止重复set
        if (CAN_SET_EXCEPTION.compareAndSet(true, false)) {
            this.t = t;
            invokeListeners(failureListeners);
            invokeListeners(finallyListeners);
        }
    }


    public V getResult() {
        return res;
    }

    public Throwable getException() {
        return t;
    }

    public EnhanceFutureTask<V> addSuccessListener(FutureListener<EnhanceFutureTask<V>> listener) {
        if (successListeners == null) {
            successListeners = new ArrayList<>();
        }
        successListeners.add(listener);
        return this;
    }

    public EnhanceFutureTask<V> addFailureListener(FutureListener<EnhanceFutureTask<V>> listener) {
        if (failureListeners == null) {
            failureListeners = new ArrayList<>();
        }
        failureListeners.add(listener);
        return this;
    }


    public EnhanceFutureTask<V> addCancelListener(FutureListener<EnhanceFutureTask<V>> listener) {
        if (cancelListeners == null) {
            cancelListeners = new ArrayList<>();
        }
        cancelListeners.add(listener);
        return this;
    }

    public EnhanceFutureTask<V> addFinallyListener(FutureListener<EnhanceFutureTask<V>> listener) {
        if (finallyListeners == null) {
            finallyListeners = new ArrayList<>();
        }
        finallyListeners.add(listener);
        return this;
    }

    private void invokeListeners(List<FutureListener<EnhanceFutureTask<V>>> listeners) {
        ofNullable(listeners)
                .ifPresent(listenerList -> listenerList.forEach(listener -> listener.handle(this)));
    }


}
